Computer applications are often programmed to interface with an operating system that provides various functions to the applications. For example, operating systems can provide lower-level services such as device drivers and memory management routines, or higher-level services such as graphical user interface application programming interfaces (“APIs”). In some cases, a particular application may only be provided for a particular operating system. For example, an application may be implemented on one or more versions of Windows®, but may not have been ported to Unix® or other operating systems.
Computer applications are also often limited to certain instruction set architectures. For example, an application can be compiled into binary code for one instruction set architecture, e.g., x86. This binary code generally will not execute on a different instruction set architecture, e.g., a PowerPC processor. Rather, different compiled binaries normally need to be generated for each instruction set architecture on which the application is expected to run.
Traditional techniques to allow application portability across operating systems and instruction set architectures tend to be relatively inefficient and cumbersome. For example, virtual machine monitors can allow a copy of a guest operating system to execute on a computer system with a different underlying host operating system. However, this approach generally involves executing full copies of both the guest operating system as well as the underlying host operating system. Likewise, central processing unit (“CPU”) emulators can be used to translate code into different instruction sets at runtime instead of using precompiled binaries. However, these emulators generally have a substantial memory and processor footprint that do not lend them to efficient integration with a guest operating system executing on a virtual machine.